package com.sky.demo.redis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.params.SetParams;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RedisLock {


    private static String SET_SUCCESS = "OK";
    private static String KEY_PRE = "REDIS_LOCK_";
    private static Long LOCK_EXPIRSE_TIME = 5000L;
    private static Long TRY_LOCK_EXPIRE_TIME = 3000L;
    private DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");

    public String lock(String key){
        Jedis jedis = null;
        try{
            jedis = new Jedis("127.0.0.1", 6379);
            key = KEY_PRE + key;
            String value = this.fetchLockValue();
            if(SET_SUCCESS.equals(jedis.set(key, value, SetParams.setParams().nx().ex(LOCK_EXPIRSE_TIME)))){
                return value;
            }
        }finally {
            jedis.close();
        }
        return null;
    }


    public String tryLock(String key){
        Jedis jedis = null;
        try {
            jedis = new Jedis("127.0.0.1", 6379);
            key = KEY_PRE + key;
            String value = this.fetchLockValue();
            long firstTryTime = System.currentTimeMillis();
            do {
                if (SET_SUCCESS.equals(jedis.set(key, value, SetParams.setParams().nx().ex(LOCK_EXPIRSE_TIME)))) {
                    return value;
                }
                TimeUnit.SECONDS.sleep(100);
            } while (System.currentTimeMillis() - TRY_LOCK_EXPIRE_TIME < firstTryTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            jedis.close();
        }
        return null;
    }

    public boolean unLock(String key, String value) {
        Long RELEASE_SUCCESS = 1L;
        Jedis jedis = null;
        try {
            jedis = new Jedis();
            key = KEY_PRE + key;
            String command = "if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            if (RELEASE_SUCCESS.equals(jedis.eval(command, Collections.singletonList(key), Collections.singletonList(value)))) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            jedis.close();
        }
        return false;
    }

    private String fetchLockValue(){
        return UUID.randomUUID().toString() + sdf.format(new Date());
    }
}
